#include "syscall.h"
typedef int bool;

#define true 1
#define false 0
#define NULL 0

/*----------------================Content of customer.c================-----------------*/
#define MAX_CRNum 3 
#define MAX_ClerkNum 3
#define MAX_StockBoyNum 3
#define MAX_CustomerNum 20

#define MinPrices 1
#define PriceFactor 100

/*Environment Varible*/
int CRNum;
int ClerkNum;
int StockBoyNum;
int CustomerNum;
#define AisleNum 5
#define ItemNum 10

/*Tricks*/
/*These Varibles is used to create specific scenario for test cases*/
int ReturnChance;					/*The chance if a customer to be return customer*/
int LostChance;						/*The chance a customer fails to find an item*/
int OriginItemAmount;					/*Origin Amount of each Item*/
int MinBoughtEach;					/*Min number of items a customer can buy*/
int MaxBoughtEach;					/*Max number of items a customer can buy is [MinBoughtEach+MaxBoughtEach-1]*/
int BornLazy;						/*If a clerk will go to rest as soon as he is created?*/
/*int PriceFactor;*/					/*The Factor that affects randomly generated prices*/
/*int MinPrice;*/						/*The Mininum price can be generated*/
bool ManagerTrackLine;					/*Does Manager keep track of Line himself*/
bool CustomerBusyWaiting;
int ProgramRun;
int TotalSales;						/*record the total sales amount.*/

/*Locks*/
int initLock;
int idLock;							/*Lock to pretect id from race condition*/
int OpLock1;							/*StartLine Exclusion*/
int OpLock2;							/*StockBoy Break Exclusion*/
int OpLock3;							/*Clerk Break Exclusion*/
int OpLock4;							/*Leaving Customer Exclusion*/
int OpLock5;							/*For StockRoom Condition Check	*/
int TableLock[MAX_CRNum];				/*Acquire this Lock before handle items on table*/
int CheckQueue;							/*Acquire this lock before check Line Lengths*/
int ScreenLock[MAX_CRNum];				/*Acquire this Lock before interact with cash register machine*/
int StockRoomLock;						/*The Lock on StockRoom*/
int ServiceButtonLock;					/*The Lock to protect service button*/
int ClerkCallLock;						/*The Lock to protect clerk call flag*/
int StockBoyStatusLock;					/*The Lock to protect Stock Boy Status*/
int AisleHelpLock[AisleNum];		/*The Lock to protect AisleHelp related monitor varibles*/
int AisleLock[AisleNum];			/*Acquire this Lock before access any item on an aisle*/
int ServiceStateLock[MAX_StockBoyNum];	/*The Lock to protect help state between a stock boy and a customer*/

/*CVs*/
int StartLine;							/*the start line*/
int ClerkOnBreak;						/*The Condition that clerks on break wait on*/
int StockBoyOnBreak;					/*The Condition that stockboys on break wait on*/
int Queue[MAX_CRNum];					/*Paying Lines*/
int Screen[MAX_CRNum];					/*The cash register machine screen State Condition*/
int Table[MAX_CRNum];					/*The Cashier Table State Condition*/
int LackMoney[MAX_CRNum];				/*If a cash register lacks money to pay return customer, he waits for Manager here*/
int StockRoomCV;						/*The Condition on which Stock Boy wait for room*/
int WaitForRestockCV[ItemNum];			/*Customers waiting for item to be restocked. It is protected by AisleLock*/
int ServiceStateCV[MAX_StockBoyNum];	/*The State Condition when a stock boy is helping a customer*/
int AisleHelpCV[AisleNum];				/*The Condition a customer waits on before a stock boy comes to serve him*/
/*Synchronization Define End*/

/*Shared Varible End*/
int AisleNeedRestock;	/*record if an aisle need to be restocked*/
int ServiceButtonOn;	/*false*/
						/*If somebody pressed service button?*/
int ClerkCall;  	/*false;*/					/*If somebody ask for more clerk?*/
int ClerkCallId;					/*The Clerk who asked manager to wake another clerk*/

int QueueLength;			/*Lengths of paying Lines*/
int ClerkOnWork;			/*If a Clerk is ready for customer?*/
		
int TableArea;				/*Place to put items*/
int CashArea;				/*Place to put money*/

int data;					/*The data is the place to exchange information with cash register*/
int MoneyCollected;			/*The money each cash register earned before manager empty it*/
int TotalMoneyCollected;		/*The money each cash register ever earned*/
int MoneyLacked;			/*The money a cash register lacks to pay a return customer*/

int StockBoyInRoom;			/*Id of StockBoy currently in Stock Room*/

int StockBoyStatus;			/*Each StockBoy's status.If he is in an aisle, status is the aisle number or aisle+AisleNum; Otherwise,  -1*/
int AisleHelpLineLength;		/*The number of customer waiting for help on each aisle*/
int Booklet;				/*The booklet used by Customer and StockBoy to exchange information*/

int CustomerLeaving;			/*Total number of customers that finished shopping and left*/

int DidSomething;               /*[MAX_StockBoyNum];*/
int Prices;
int ItemAmount;
int ItemRestockPrediction;

/*ID Assignment*/
int nextManagerID;
int nextCustomerID;
int nextClerkID;
int nextStockBoyID;
int nextCashRegisterID;

int GenRandom(int limit)
{
	return Random(limit);
}

int modifyName(char * name, int offset, int num)
{
	int i=0;
	int pos=0;
	int digit;
	if(name == NULL) return -1;
	while(name[i]!='\0' && i<offset+4){
		i++;
	}
	if(name[i]=='\0' && i < offset+4) return -1;
	pos= i-1;
	while(num!=0){
		digit=num%10;
		num = (num-digit)/10;
		name[pos]=(char)(digit+48);
		pos--;
	}
	for(;pos>=offset;pos--)
		name[pos]='0';
	return 1;
}

void initialize()
{
	char* name;
	int numbers[6];
	int i;
		
	nextManagerID = CreateMV("nextManagerID",13,1,0);
	nextCustomerID = CreateMV("nextCustomerID",14,1,0);
	nextClerkID = CreateMV("nextClerkID",11,1,0);
	nextStockBoyID = CreateMV("nextSBID",14,1,0);
	nextCashRegisterID = CreateMV("nextCRID",18,1,0);

	CRNum = GetMV(CreateMV("CRNum",5,1,MAX_CRNum),0);
	ClerkNum = GetMV(CreateMV("ClerkNum",8,1,MAX_ClerkNum),0);
	StockBoyNum = GetMV(CreateMV("StockBoyNum",11,1,MAX_StockBoyNum),0);
	CustomerNum = GetMV(CreateMV("CustomerNum",11,1,MAX_CustomerNum),0);	

	OpLock1 = RemoteCreateLock("OperationLock1",15); 		
	OpLock2 = RemoteCreateLock("OperationLock2",15);
	OpLock3 = RemoteCreateLock("OperationLock3",15);
	OpLock4 = RemoteCreateLock("OperationLock4",15);
	OpLock5 = RemoteCreateLock("OperationLock5",15);
	idLock= RemoteCreateLock("IDLock",7);
	StartLine =  RemoteCreateCondition("StartLine",10);
	ClerkOnBreak =  RemoteCreateCondition("ClerkBreak",11);
	StockBoyOnBreak =  RemoteCreateCondition("StockBoyBreak",14);
	CheckQueue = RemoteCreateLock("CheckQueueLock",15);
	StockRoomLock = RemoteCreateLock("StockRoomLock",14);
	StockRoomCV = RemoteCreateCondition("StockRoomCV",12);
	ServiceButtonLock = RemoteCreateLock("ServiceButtonLock",18);
	StockBoyStatusLock = RemoteCreateLock("StockBoyStatusLock",19);
	ClerkCallLock=RemoteCreateLock("ClerkCallLock",14);

	/*MV initialize*/
	ReturnChance = CreateMV("ReturnChance",12,1,20);	/*The chance if a customer to be return customer*/
	LostChance = CreateMV("LostChance",10,1,25);		/*The chance a customer fails to find an item*/
	OriginItemAmount = CreateMV("OriginItemAmount",16,1,3);	/*Origin Amount of each Item*/
	MinBoughtEach = CreateMV("MinBoughtEach",13,1,1);	/*Min number of items a customer can buy*/
	MaxBoughtEach = CreateMV("MaxBoughtEach",13,1,10);	/*Max number of items a customer can buy is [MinBoughtEach+MaxBoughtEach-1]*/
	/*PriceFactor = CreateMV("PriceFactor",11,1,100);*/		/*The Factor that affects randomly generated prices*/
	/*MinPrice = CreateMV("MinPrice",8,1,0);*/			/*The Mininum price can be generated*/
	ManagerTrackLine = CreateMV("ManagerTrackLine",16,1,true);/*Does Manager keep track of Line himself*/
	
	ProgramRun=CreateMV("ProgramRun",10,1,true);
	TotalSales=CreateMV("TotalSales",10,1,0);
	CustomerBusyWaiting = CreateMV("CustomerBusyWaiting",19,1,false);
	ServiceButtonOn=CreateMV("ServiceButtonOn",15,1,0);
	ClerkCall=CreateMV("ClerkCall",9,1,0);
	ClerkCallId=CreateMV("ClerkCallId",11,1,-1);
       	StockBoyInRoom=CreateMV("StockBoyInRoom",14,1,-1);
       	CustomerLeaving=CreateMV("CustomerLeaving",15,1,0);
	
	/*For CR-related MV*/
	QueueLength=CreateMV("QueueLength",11,CRNum,0);
	ClerkOnWork=CreateMV("ClerkOnWork",11,CRNum,1);
	BornLazy=CreateMV("BornLazy",8,CRNum,0);
	TableArea=CreateMV("TableArea",9,CRNum,-1);	
	CashArea=CreateMV("CashArea",8,CRNum,0);
	data=CreateMV("data",4,CRNum,-1);			/*-1 is used to denote initial state for cash register*/
	MoneyCollected=CreateMV("MoneyCollected",14,CRNum,0);
	TotalMoneyCollected=CreateMV("TotalMoneyCollected",19,CRNum,0);
	MoneyLacked=CreateMV("MoneyLacked",11,CRNum,-1);

	/*For stockboy-related MV*/
	Booklet=CreateMV("Booklet",7,StockBoyNum,-1);	
	StockBoyStatus = CreateMV("StockBoyStatus",14,StockBoyNum,-1);/*StockBoyStatus == -1 means he is out of any aisle*/
	DidSomething=CreateMV("DidSomething",12,StockBoyNum,false);

	/*For aisle-related MV*/
	AisleNeedRestock=CreateMV("AisleNeedRestock",16,AisleNum,0);	/*no aisle need to be restocked at very beginning*/
	AisleHelpLineLength=CreateMV("AisleHelpLineLength",19,AisleNum,0);/*originally no customer is waiting for help in any aisle*/
	/*Initialization of array varibles declared*/

	/*For item-related MV*/
	Prices=CreateMV("Prices",6,ItemNum,0);
	ItemRestockPrediction=CreateMV("ItemRestockPrediction",21,ItemNum,0);/*Item to be restocked is 0	*/
	ItemAmount = CreateMV("ItemAmount",10,ItemNum,3);	/*Origin Amount of each Item*/
	
	for(i=0;i<CRNum;i++)
	{
		/*char* name;*/
		name="Queue0000";
		modifyName(name,5,i);	
		Queue[i] = RemoteCreateCondition(name,9);
		
		name="TableLock0000";
		modifyName(name,9,i);
		TableLock[i]=RemoteCreateLock(name,13);
		
		name="Table0000";
		modifyName(name,5,i);
		Table[i]=RemoteCreateCondition(name,9);
		
		name="ScreenLock0000";
		modifyName(name,10,i);
		ScreenLock[i]=RemoteCreateLock(name,14);
			
		name="Screen0000";
		modifyName(name,6,i);
		Screen[i]=RemoteCreateCondition(name,10);
		
		name="Lack0000";
		modifyName(name,4,i);
		LackMoney[i]=RemoteCreateCondition(name,8);
	}

	for(i=0;i<StockBoyNum;i++)
	{
		name="ServiceStateLock0000";
		modifyName(name,16,i);
		ServiceStateLock[i]=RemoteCreateLock(name,20);
		
		name="ServiceState0000";
		modifyName(name,12,i);
		ServiceStateCV[i]=RemoteCreateCondition(name,16);
	}

	for (i=0;i<AisleNum;i++)
	{
		name="AisleHelpLock0000";
		modifyName(name,13,i);
		AisleHelpLock[i]=RemoteCreateLock(name,17);
		
		name="AisleHelpCV0000";
		modifyName(name,11,i);
		AisleHelpCV[i]=RemoteCreateCondition(name,15);
		
		name="AisleLock0000";
		modifyName(name,9,i);
		AisleLock[i]=RemoteCreateLock(name,13);
	}
	
	for(i=0;i<ItemNum;i++)
	{
		name="WaitForRestockCV0000";
		modifyName(name,16,i);
		WaitForRestockCV[i]=RemoteCreateCondition(name,20);
	}
}
/*---------------------Customer Minor--------------------*/
/*Customer Behavior*/
/*	the main Logic of a Customer*/
/*-------------------------------------------------------*/

void WaitForStart()
{
	RemoteAcquireLock(OpLock1);
	RemoteWaitCondition(StartLine,OpLock1);
	RemoteReleaseLock(OpLock1);
}

int GetAisleByItem(int item)
{
	return (item/2);
}

void
PressServiceButton()								/*Press the service button*/
{
	RemoteAcquireLock(ServiceButtonLock);
	SetMV(ServiceButtonOn,0,1);
	RemoteReleaseLock(ServiceButtonLock);
}


int
AskStockBoyForItem(int item,int id)					/*When customer ask stock boy for position of item*/
{
	int numbers[6];
	int helpAisle = -1;
	int myStockBoy = -1;
	int myAisle = -1;
	int i,j,temp;
	
	/*find an aisle number depending on the stockboy's Status.*/
	/*We will enter aisles one by one, and see if there is a StockBoy whose Status == aisleID; If yes, we know there is one workging in current aisle ,and wait here*/
	while(true)
	{
		for(i=0; i<AisleNum; i++)				/*Enter	aisles one by one			*/
		{
			RemoteAcquireLock(AisleHelpLock[i]);			/*Once in an aisle, acquire its aisle help lock*/
			for(j=0; j<StockBoyNum; j++)
			{
				/* between the steps a customer find a stockboy, and increase the aisleHelpLine, */
				/* the stockboy has no chance to run*/
				RemoteAcquireLock(StockBoyStatusLock);
				if( (GetMV(StockBoyStatus,j)!= -1) && ( GetMV(StockBoyStatus,j) % AisleNum == i) )/*if there is a stock boy in current aisle, remember this aisle*/
				{
					RemoteReleaseLock(StockBoyStatusLock);
					helpAisle = i;
					break;
				}
				RemoteReleaseLock(StockBoyStatusLock);

			}
			if(helpAisle != -1)						/*helpAisle!=-1 means we found a stockboy, break without releasing AisleHelpLock*/
				break;
			RemoteReleaseLock(AisleHelpLock[i]);					/*Otherwise, release lock, look another aisle*/
		}
			
		if(helpAisle == -1)							/*looked into all aisles and found no stockboy*/
		{
			if(GetMV(CustomerBusyWaiting,0))					/*This trick is only used in scenario that without manager.*/
				continue;
			numbers[0]=id;
			WriteFormat("Customer [%d] looked in all aisle for StockBoy. He is now requesting help by pressing service button.\n",103,numbers, 1);
			PressServiceButton();					/*press service button*/
			WaitForStart();							/*wait on start line for calling from manager when stockboy is ready*/
			WriteFormat("Customer got call from manager and wake up.\n",45,0,0);
			continue;								/*when waken uo by manager, go back to head of this function, re do task*/
		}
		else										/*We found a stock boy in aisle*/
		{
			/*printf("===Customer [%d] find a stockboy in aisle [%d], get in line\n", id, helpAisle);*/
			temp=GetMV(AisleHelpLineLength,helpAisle);
			SetMV(AisleHelpLineLength,helpAisle,temp+1);/*AisleHelpLineLength[helpAisle]++;		/*Change help line length*/
			RemoteWaitCondition(AisleHelpCV[helpAisle],AisleHelpLock[helpAisle]);			/*wait in help CV*/
			RemoteReleaseLock(AisleHelpLock[helpAisle]);				/*After wake up, release help lock: help line length should have been decremented by stock boy*/

			/* find which stockboy is ready for helping me*/

			/*printf("===Customer [%d] is told one stockboy is waiting for him, he is searching status [%d] in aisle [%d]\n", id, helpAisle + AisleNum,helpAisle);*/
		
			RemoteAcquireLock(StockBoyStatusLock);
			for(i=0; i<StockBoyNum; i++)		/*look which stockboy said to serve me */
			{
				/*printf("StockBoy #%d Status: %d, I am searching for status %d\n",i,StockBoyStatus[i],helpAisle+AisleNum);*/
				if(GetMV(StockBoyStatus,i)== helpAisle + AisleNum)/*A stock boy ready to serve will set his status to [ AisleNumber + AisleNum  ]*/
				{
					SetMV(StockBoyStatus,i,helpAisle);	/*Reset this stockboy's Service status, so that other customer won't ask him at the same time*/
					myStockBoy = i;
					break;
				}
			}
			RemoteReleaseLock(StockBoyStatusLock);
			
			numbers[0]=id;
			numbers[1]=myStockBoy;
			WriteFormat("Customer [%d] is asking for assistance from StockBoy [%d]\n",59,numbers,2);
		
			/*Start interaction with stockboy*/
			RemoteAcquireLock(ServiceStateLock[myStockBoy]);
		
			SetMV(Booklet,myStockBoy,id);				/*First, tell stockboy my id*/
			
			RemoteSignalCondition(ServiceStateCV[myStockBoy],ServiceStateLock[myStockBoy]);
			RemoteWaitCondition(ServiceStateCV[myStockBoy],ServiceStateLock[myStockBoy]);	
			
			/*printf("=== %s ask a question: where is item%d\n", name, item);*/
			SetMV(Booklet,myStockBoy,item);				/*Then, tell stockboy the item I want */
			RemoteSignalCondition(ServiceStateCV[myStockBoy],ServiceStateLock[myStockBoy]);	
			RemoteWaitCondition(ServiceStateCV[myStockBoy],ServiceStateLock[myStockBoy]);		
			
			myAisle =GetMV(Booklet,myStockBoy);			/*Then, get answer from stockboy*/
			RemoteSignalCondition(ServiceStateCV[myStockBoy],ServiceStateLock[myStockBoy]);	/*Tell stockboy I am satisfied*/
			
			numbers[0]=id;
			numbers[1]= myAisle;
			numbers[2]= myStockBoy;
			WriteFormat("Customer [%d] got aisle [%d] from StockBoy [%d]\n" , 49, numbers, 3);
			RemoteReleaseLock(ServiceStateLock[myStockBoy]);
			/*Interaction with stockboy end*/

			return myAisle;
		}
	}
}


void
GetItem(int item)
{
	int aisle = GetAisleByItem(item);				/*Fetch the aisle number*/
 

	/*WriteFormat("Get item on aisle %d \n",23,&aisle,1);
	WriteFormat("aisle lock is %d \n",19,AisleLock+aisle,1);*/


	RemoteAcquireLock(AisleLock[aisle]);					/*Enter Aisle*/

	while(true)
	{
		if(GetMV(ItemAmount,item)>0)						/*If Item is not empty, get it and leave*/
		{
			SetMV(ItemAmount,item,GetMV(ItemAmount,item)-1);
			break;
		}
		else										/*Else, wait for it to be restocked*/
		{
			/*Item Not Enough, have to wait*/
			WriteFormat("Customer try to wake on 'WaitForRestockCV'\n",44,0,0);
			RemoteWaitCondition(WaitForRestockCV[item],AisleLock[aisle]);
			continue;								/*When told item is restocked, redo GetItem();*/
		}
	}

	SetMV(AisleNeedRestock,aisle,true);					/*Since I just fetched that item, lit Aisle light saying this aisle nees restock*/
	RemoteReleaseLock(AisleLock[aisle]);
}

void 
CallManagerForClerk()								/*If there is no clerk available, call manager*/
{
	RemoteAcquireLock(ClerkCallLock);
	SetMV(ClerkCall,0,true);
	RemoteReleaseLock(ClerkCallLock);
}

int
FindShortestQueueAndWait(int id)					/*find the shortest queue, and wait there*/
{
	int people=1000000;							/*RAND_MAX is the biggest integer defined*/
	int number = -1;
	int numbers[6];
	int i;
	while(true)
	{
		RemoteAcquireLock(CheckQueue);
	
		for(i=0;i<CRNum;i++)					/*loop all lines*/
		{
			if(!GetMV(ClerkOnWork,i))						/*If that line is closed, check next*/
				continue;

			if(GetMV(QueueLength,i)<people)				/*If Line length is shorter, remember his number and line length*/
			{
				people=GetMV(QueueLength,i);
				number=i;
			}
		}

		if(number == -1)							/*No Line is picked, means All line is closed, shoule call manager*/
		{
			/*printf("Customer %d: can't find any clerk, call manager!!!\n",id);*/
			CallManagerForClerk();					/*Call manager*/
			RemoteReleaseLock(CheckQueue);
			WaitForStart();							/*wait in start line, the manager will call him*/
			continue;								/*Redo Find Shortest after wakeup*/
		}

		numbers[0]=id;
		numbers[1]=number;
		numbers[2]=people;
		WriteFormat("Customer [%d] chose Clerk [%d] with line length of [%d]\n",57,numbers, 3);/*When called by clerk, start to show bought item*/

		SetMV(QueueLength,number,GetMV(QueueLength,number)+1);						/*Add self to that line*/
		RemoteWaitCondition(Queue[number],CheckQueue);			/*Wait*/
		SetMV(QueueLength,number,GetMV(QueueLength,number)-1);						/*When awake from wait, leave the line to stand in front of table*/
		RemoteReleaseLock(CheckQueue);
		return number;
	}
}

void
ShowItem(int item,int queueNumber)					/*show item to clerk on queueNumber*/
{
	SetMV(TableArea,queueNumber,item);
	RemoteSignalCondition(Table[queueNumber],TableLock[queueNumber]);
	RemoteWaitCondition(Table[queueNumber],TableLock[queueNumber]);
}

int
TellClerkToCountAndPay(int queueNumber,int id, bool ret)/*Tell clerk transaction over*/
{
	int numbers[6];
	int total;
	ShowItem(-1,queueNumber);						/*According to protocol, show clerk -1 means transaction is over*/
	total = GetMV(CashArea,queueNumber);			/*Get the total cost returned from clerk*/
	RemoteSignalCondition(Table[queueNumber],TableLock[queueNumber]);	/*Tell clerk I acknowladged the total cost*/
	
	numbers[0]=id;
	numbers[1]=total/10;
	numbers[2]=total%10;
	numbers[3]=queueNumber;
	/*numbers[1]=total;*/
	/*numbers[2]=queueNumber;*/
	if(ret){
		WriteFormat("Customer [%d] receives [%d.%d] from Clerk [%d] and is now waiting for receipt.\n", 83, numbers, 4);
	}
	else{
		WriteFormat("Customer [%d] pays [%d.%d] to Clerk [%d] and is now waiting for receipt.\n", 77, numbers, 4);
	}
	RemoteWaitCondition(Table[queueNumber],TableLock[queueNumber]);	/*wait for clerk to do something*/
	
	return total;
}

void
Leave(int queueNumber)									/*Cuatomer leave the store*/
{
	RemoteSignalCondition(Table[queueNumber],TableLock[queueNumber]);	/*Tell clerk I left*/
	RemoteAcquireLock(OpLock4);						/*Add leaving customer statistics. Manager will rely on this to close sstore*/
	SetMV(CustomerLeaving,0,GetMV(CustomerLeaving,0)+1);
	/*printf("Total Finished Customer : %d\n", CustomerLeaving);*/
	RemoteReleaseLock(OpLock4);
}

/*---------------------Customer Major--------------------*/
/*Customer Behavior*/
/*	the main Logic of a Customer*/
/*-------------------------------------------------------*/

void
CustomerBehavior()
{
	/*need to have a lock!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
	int id;
	int numbers[6];
	int MAX_TotalNum = 100;
	int Items[MAX_TotalNum];
	int QueueNumber;
	int i;
	bool retCustomer;
	int tmp;
	int TotalNum;
	RemoteAcquireLock(idLock);
	id=GetMV(nextCustomerID,0);
	SetMV(nextCustomerID,0,id+1);
	RemoteReleaseLock(idLock);

	
	/*NEEDN'T WORRY LOCAL VARIBLES, THEY ARE STORED IN STACK, AND WON'T BE MANIPULATED BE OTHER THREADS*/
	retCustomer = false;							/*Am I a return customer?*/

	tmp = GenRandom(100);							/*Roll the dice to decide if I am a return customer*/
	if(tmp<GetMV(ReturnChance,0))
		retCustomer = true;

	TotalNum = GetMV(MinBoughtEach,0)+GenRandom(GetMV(MaxBoughtEach,0));/*Randomly generate total Number of items to buy. Assuming buy no more than MaxBoughtEach*/
	numbers[0]=id;
	numbers[1]=TotalNum;
	if(retCustomer)										/*Start purchasing*/
		WriteFormat("Customer [%d] needs to return [%d] no.of item.\n", 48, numbers, 2);
	else
		WriteFormat("Customer [%d] wants to buy [%d] no.of items.\n",46, numbers, 2);	

	/*Items = (int*)malloc(TotalNum*sizeof(int));*/
	/*int * Items = new int[TotalNum];*/					/*Generate Item List */
	for(i=0;i<TotalNum;i++)				
	{
		Items[i]=GenRandom(ItemNum);					/*Randomly generate item id*/
		
		if(retCustomer)									/*Return customer don't need to fetch items.*/
			continue;

		tmp = GenRandom(100);							/*Roll the dice to decide if customer fail to find the item*/
		if(tmp<GetMV(LostChance,0))								/*If failed, customer have to look for a stockboy for help*/
		{
			numbers[0]=id;
			numbers[1]=Items[i];
			WriteFormat("Customer [%d] is not able to find item [%d] and is searching for StockBoy.\n",76, numbers,2);
			AskStockBoyForItem(Items[i],id);			/*Ask StockBoy for help*/
		}
		WriteFormat("Customer try to get Item\n",26,0,0);
		GetItem(Items[i]);								/*Take the item;	*/
		/*printf("Customer %s: Bought item %d\n",name,Items[i]);*/
	}
	
	WriteFormat("Customer %d: Finished purchasing, trying to find a paying queue\n",65,&id,1);
	/*printf("Customer %s: Finished purchasing, trying to find a paying queue\n",name);//finish purchasing,trying to find a queue*/
	
	QueueNumber = FindShortestQueueAndWait(id);		/*find the shortest queue, and wait there*/
	RemoteAcquireLock(TableLock[QueueNumber]);			/*Make Critical Section*/
	
	ShowItem(id,QueueNumber);							/*Tell Clerk my name*/

	if(retCustomer)
		ShowItem(1,QueueNumber);
	
	else
		ShowItem(0,QueueNumber);
	
	/*ShowItem((retCustomer?1:0),QueueNumber);*/			/*Tell Clerk my purpose: 1,return item; 0,buy item;*/

	for(i=0;i<TotalNum;i++)							/*show items to clerk, one by one*/
	{
		numbers[0]=id;
		numbers[1]=Items[i];
		numbers[2]=QueueNumber;
		WriteFormat("Customer [%d] gives item [%d] to Clerk [%d].\n",46, numbers,3);
		ShowItem(Items[i],QueueNumber);			
	}
		numbers[0]=id;
		numbers[1]=QueueNumber;
		numbers[2]=TotalNum;
	WriteFormat("Customer [%d] tells Clerk [%d], I have given you all my [%d] items.\n",69 ,numbers,3);

	TellClerkToCountAndPay(QueueNumber, id, retCustomer);/*tell clerk to count total, and pay for them,then wait for receipt*/

	Leave(QueueNumber);									/*take recipet and leave store*/
		
	numbers[0]=id;
	numbers[1]=QueueNumber;
	WriteFormat("Customer [%d] got receipt from Clerk [%d] and is now leaving.\n", 63, numbers, 2);
	
	RemoteReleaseLock(TableLock[QueueNumber]);			/*Critical Section End*/
}
/*----------------================Content of customer.c================-----------------*/


int main()
{
	int i,j;
	bool loop = true;
	int numbers[6];
	int CustomerNum = GetMV(CreateMV("CustomerNum",11,1,MAX_CustomerNum),0);
	int CustomerLeavingID = CreateMV("CustomerLeaving",15,1,0);
	
	while(loop)
	{
		int CustomerLeaving = GetMV(CustomerLeavingID,0);
		WriteFormat("---------------------------------\n",35,0,0);
		WriteFormat("[Customer Controller Panel]\n",29,0,0);
		WriteFormat("Manager Expects #%d Customers\n",31,&CustomerNum,1);
		WriteFormat("#%d Customers Alread visited Home Depot\n",41,&CustomerLeaving,1);
		
		if(CustomerLeaving >= CustomerNum)
		{
			WriteFormat("Home depot has served customers more than expected, cannot serve more\n",71,0,0);
			WriteFormat("----------------------------\n",30,0,0);
			break;
		}
	
		j = ReadInput("How many Customer do you want to create?(1~20)(type -1 to quit)",46);
		if(j == -1)
		{
			WriteFormat("Good Bye !!\n",13,0,0);
			break;
		}
		if(j<1 || j>20)
		{
			WriteFormat("Sorry, Customer Num has to be between 1 and 20\n\n\n",52,0,0);
			continue;
		}	
		WriteFormat("----------------------------\n",30,0,0);
		
		loop = false;

		for(i=0;i<j;i++)
		{
			Exec("../test/customer",16);
			Yield();
		}
		/*Run one customer instance myself*/
		/*initialize();
		CustomerBehavior();*/
	}

	Exit(0);
}

